#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <tchar.h>
#include <ctype.h>

#include "resource.h"



#define susx 100
#define susy 100

int xMouse,yMouse;

struct Stack
{
	int key;
	Stack *next;
};

Stack *stiva_spaghetti[100];
int contor_stive=0;
Stack *Head=0;
int nod_ales=0;
int nod_recent=0;

// functii stiva principala
Stack* adaugare_stiva(Stack *head);
void adaugare_nod_spaghetti(int val, Stack *nod_ales);
int contor_chei(int val);
int contor_noduri_cheie(Stack *node);
int verificare_head(Stack *node, int &index);


Stack *cautare_stiva_dupa_cheie(int data);
int verificare_ramura_nod_recent( Stack *nod );


// functii stiva
void adaugare_nod_stiva(Stack *&head, int data);
void copiere_stiva(Stack *source_head, Stack *&dest_head);
Stack *alocare_memorie_nod_stiva(int data);

//winapi
BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);
bool get_text(HWND hwnd, char *text, int ID);
void insert(HWND hwnd);
void refresh_desen(HWND hwnd);
void punct(HWND hwnd,int x,int y, HBRUSH brush);
void draw_text(HWND hwnd, int x, int y, char *text);
bool verificare_desenat(int stack_index, int &index_stiva_gasit, int &index_nod_gasit, int data);
void albeste(HWND hwnd);
void verif_nod(HWND hwnd, int x, int y);
bool verificare_click_nod(int dotx, int doty, int px, int py);
HBRUSH brush_nod( HWND hwnd, Stack* p );


// windows GDI , desen
HBRUSH grayBrush=CreateSolidBrush(RGB(192,192,192));
HBRUSH rootBrush=CreateSolidBrush(RGB(3,3,3));
HBRUSH backgroundBrush=CreateSolidBrush(RGB(255,255,255));
HBRUSH redBrush=CreateSolidBrush(RGB(255,0,0));
HBRUSH greenBrush=CreateSolidBrush(RGB(0,255,0));

void desenare_linie(HWND hwnd,int x1, int y1, int x2, int y2, HBRUSH brush);


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	return DialogBox(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DlgProc);
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch(Message)
	{
		case WM_INITDIALOG:
			SetDlgItemText(hwnd, IDD_MAIN, "Spaghetti Stack");
		break;
		case WM_MOUSEMOVE: 
				{
					
					break;
				}
		case WM_LBUTTONDOWN:
			{
				xMouse = LOWORD(lParam);
				yMouse = HIWORD(lParam);

				xMouse -= susx; yMouse -= susy;

				verif_nod(hwnd, xMouse, yMouse);
				refresh_desen(hwnd);
				break;
			}
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
				case IDC_BUTTON3:
					{
						int yy;
						char s[100],sir[100],text_nod[1000];
						strcpy(s,"");
						Stack *p,*q;
						int ok=0;
						get_text(hwnd,text_nod,IDC_EDIT2);
						yy=atoi(text_nod);
						if  (yy!=NULL)
							{
								for(int i=0;i<contor_stive;i++)
								{
									q = stiva_spaghetti[i];
									p = stiva_spaghetti[i];
									while (p!=NULL && ok==0)
									{
										if (p->key==yy)
										{
											ok=1;
											i=contor_stive;
										}
										else 
											p=p->next;
									}
								}
								while (q->next!=NULL)
								{
									itoa(q->key,sir,10);
									strcat(s,sir);
									strcat(s," , ");
									q=q->next;
								}
								itoa(q->key,sir,10);
								strcat(s,sir);
								SetDlgItemText(hwnd, IDC_EDIT1, s);
								break;
						}
					}

				case ID_INSERT:
					{
						insert(hwnd);
						refresh_desen(hwnd);
						break;
					}
				case IDC_REDRAW:
					{
						refresh_desen(hwnd);
						break;
					}
				case IDC_BUTTON2:
					{
						MessageBox(hwnd,"Aplicatia se va inchide.","Warning",MB_OK);
						DestroyWindow(hwnd);
					}
				
				case WM_CLOSE:
					EndDialog(hwnd, 0);
				case WM_DESTROY:
					PostQuitMessage(0);
				break;
				default:
					return FALSE;
			}
			default:
					return FALSE;
	}
	return TRUE;
}

void verif_nod(HWND hwnd, int x, int y)
{
	int j;
	for(int i=0;i<contor_stive;i++)
	{
		j = 0;
		Stack *p = stiva_spaghetti[i];
		while ( p != 0 )
		{
			if ( verificare_click_nod(x, y, i * 100, j * 100) )
			{
				char data[10];
				data[0] = 0;
				itoa(p->key, data, 10);
				SetDlgItemText(hwnd, IDC_EDIT_NODE, data);

				return;
			}
			j++;
			p = p->next;
		}
	}
}

bool verificare_click_nod(int dotx, int doty, int px, int py)
{
	if ( (dotx > px - 15) && (dotx < px + 15) && (doty > py - 15) && (doty < py + 15) )
		return true;

	return false;
}

void refresh_desen(HWND hwnd)
{
	albeste(hwnd);
	int j;
	char tmp[100];
	for(int i=0;i<contor_stive;i++)
	{
		j = 0;
		Stack *p = stiva_spaghetti[ i ];
		while ( p != 0 )
		{
			HBRUSH brush = brush_nod(hwnd, p);

			if ( p != stiva_spaghetti[ i ] )
			{
				int index_found, index_nod;
				if ( verificare_desenat(i, index_found, index_nod, p->key) )
				{
					desenare_linie(hwnd, i * 100, (j-1)*100 + 10, index_found * 100, index_nod * 100 - 10, brush);
					break;
				}
				else
					desenare_linie(hwnd, i * 100, (j-1)*100 + 10, i * 100, j * 100 - 10, brush);
			}
			
			punct(hwnd, i * 100, j * 100, brush); 
			draw_text(hwnd, i * 100, j * 100, itoa(p->key,tmp,10));

			p = p->next;
			j++;
		}
	}
}

HBRUSH brush_nod( HWND hwnd, Stack* p )
{
	HBRUSH brush;
	brush = verificare_ramura_nod_recent( p ) ? redBrush : grayBrush;
	char data[10];
	data[0] = 0;
	get_text(hwnd, data, IDC_EDIT_NODE);
	if ( data[0] != 0 && p->key == atoi(data))
		brush = greenBrush;

	return brush;
}

bool verificare_desenat(int stack_index, int &index_stiva_gasit, int &index_nod_gasit, int data)
{
	int j;
	for(int i=0;i<stack_index;i++)
	{
		Stack *p = stiva_spaghetti[ i ];
		j = 0;
		while ( p != 0 )
		{
			if ( p->key == data )
			{
				index_stiva_gasit = i;
				index_nod_gasit = j;
				return true;
			}
			p = p->next;
			j++;
		}
	}
	return false;
}

void albeste(HWND hwnd)
{
	RECT rct;
	rct.left=0;
	rct.right=1800;
	rct.top=0;
	rct.bottom=500;
	HDC hdc=GetDC(hwnd);
	FillRect(hdc,&rct,backgroundBrush);
	ReleaseDC(hwnd, hdc);
}


void punct(HWND hwnd,int x,int y, HBRUSH brush)
{
	srand(time(NULL));
	RECT rct;
	rct.left=susx+x-15;
	rct.right=susx+x+15;
	rct.top=susy+y-15;
	rct.bottom=susy+y+15;
	HDC hdc=GetDC(hwnd);
	FillRect(hdc,&rct,brush);
	ReleaseDC(hwnd, hdc);

}

void draw_text(HWND hwnd, int x, int y, char *text)
{
    HDC hdc = GetDC(hwnd);

    TextOut (hdc,
             // Locatia textului
             x + susx - 5,
             y + susy - 5,
			 text,
             // Dimensiunea textului
             strlen (text));

	ReleaseDC(hwnd, hdc);
}

void desenare_linie(HWND hwnd,int x1, int y1, int x2, int y2, HBRUSH brush)
{
	HDC hdc=GetDC(hwnd);
	HGDIOBJ oldPen=SelectObject(hdc,brush);
	POINT pntArray[2];
	pntArray[0].x=susx + x1;
	pntArray[0].y=susy + y1;
	pntArray[1].x=susx + x2;
	pntArray[1].y=susy + y2;
	Polyline(hdc, pntArray, 2);
	ReleaseDC(hwnd,hdc);

	DeleteObject(oldPen);
}

void insert(HWND hwnd)
{
	char text_data[1000];
	char text_nod[1000];

	if ( get_text(hwnd, text_data, IDC_EDIT_DATA) )
	{
		if (isalpha(text_data[0]))
			{
				MessageBox(NULL,"Va rugam introduceti un numar","Warning",MB_OK);
				return;
			}
		int data = atoi(text_data);
		if ( get_text(hwnd, text_nod, IDC_EDIT_NODE) )
		{
			int cheie_aleasa = atoi(text_nod);
			Stack *nod_ales = cautare_stiva_dupa_cheie(cheie_aleasa);
			adaugare_nod_spaghetti(data, nod_ales);
		}
		else		
		{
			adaugare_nod_spaghetti(data, 0);
		}
	}
}

bool get_text(HWND hwnd, char *text, int ID)
{
	int l1 = GetWindowTextLength(GetDlgItem(hwnd, ID));

	if(l1 > 0 )
	{
		GetDlgItemText(hwnd, ID, text, 999);

		return 1;
	}
	else
	{
		return 0;
	}
}


void adaugare_nod_spaghetti(int val, Stack *nod_curent)
{
	if ( nod_curent==NULL && contor_stive>0) 
		{	
			MessageBox(NULL, "Selectati nod. ", "Warning", MB_OK);
			return;
		}	

	if ( contor_chei(val) != 0 ) 
		{
			MessageBox(NULL, "Cheie existenta. Reintroduceti alta cheie ", "Warning", MB_OK);
			return;
		}

	int index_head;

	if (verificare_head(nod_curent,index_head ) )
	{
		adaugare_nod_stiva(stiva_spaghetti[index_head],val);
	}
	else
	{
		if (nod_curent!=NULL)
		{
			Stack *newHead = 0;
			copiere_stiva(nod_curent,newHead);
			adaugare_nod_stiva(newHead,val);
			adaugare_stiva(newHead);
		}
		else		
		{
			Head=adaugare_stiva(alocare_memorie_nod_stiva(val));
		}
	}

	nod_recent=val;
}

int verificare_ramura_nod_recent( Stack *nod)
{
	Stack *p=cautare_stiva_dupa_cheie(nod_recent);
	while(p!=NULL)
	{
		if (p->key==nod->key)
			return 1;
		p=p->next;
	}

	return 0;
}

int contor_noduri_cheie(Stack *nod)
{
	if (nod==NULL)
		return 0;
	int contor=contor_chei(nod->key);
	return contor;
}

int verificare_head(Stack *nod, int &index)
{
	for(int i=0;i<contor_stive;i++)
		if (stiva_spaghetti[i]==nod)
		{
			index=i;
			return 1;
		}
	return 0;
}

int contor_chei(int val)
{
	int contor=0;
	Stack *p;

	for(int i=0;i<contor_stive;i++)
	{
		p=stiva_spaghetti[i];
		while ( p!=NULL)
		{
			if (p->key==val)
				contor++;
			p=p->next;
		}
	}
	return contor;
}

Stack* adaugare_stiva(Stack *head)
{
	stiva_spaghetti[contor_stive]=head;
	contor_stive++;
	return stiva_spaghetti[contor_stive-1];
}

void adaugare_nod_stiva(Stack *&head, int data)
{
	Stack *p=alocare_memorie_nod_stiva(data);
	p->next=head;
	head=p;
}

void copiere_stiva(Stack *source_head, Stack *&dest_head)
{
	if (source_head==NULL)
		return;
	dest_head=alocare_memorie_nod_stiva(source_head->key);
	Stack *p=dest_head, *source_pointer=source_head->next;
	while (source_pointer!=NULL)
	{
		p->next=alocare_memorie_nod_stiva(source_pointer->key);
		p=p->next;
		source_pointer=source_pointer->next;
	}
}

Stack *alocare_memorie_nod_stiva(int data)
{
	Stack *p=(Stack*)malloc(sizeof(Stack));
	p->key=data;
	p->next=NULL;
	return p;
}

void afisare_stiva_dupa_cheie()
{
	char s[100],sir[100],text_nod[1000];
	HWND hwnd;
	Stack *p,*q;
	int ok=0;
	if  (get_text(hwnd,text_nod,IDC_EDIT2))
	{
		for(int i=0;i<contor_stive;i++)
			{
				q = stiva_spaghetti[i];
				p = stiva_spaghetti[i];
				while (p!=NULL)
					{
						if (p->key==atoi(text_nod))
							{
								ok=1;
								i=contor_stive;
							}
						else 
							p=p->next;
					}
			}
		while (q->next!=NULL)
			{
				itoa(q->key,sir,10);
				strcat(s,sir);
				strcat(s," , ");
				q=q->next;
			}
		itoa(q->key,sir,10);
		strcat(s,sir);
		SetDlgItemText(hwnd, IDC_EDIT2, s);
	
	}
}


Stack *cautare_stiva_dupa_cheie(int data)
{
	Stack *p;
	for(int i=0;i<contor_stive;i++)
	{	
		p = stiva_spaghetti[i];
		while (p!=NULL)
		{
			if (p->key==data)
				return p;
			p=p->next;
		}
	}
	return 0;
}

